import moment from 'moment';

/**
 * 类型定义
 */
type DateValue = string | number | Date;
interface AutoObjValue {
  [key: string]: any;
}

class Utils {
  /**
   * 空数据占位符
   */
  placeholder = '--';
  connect = '__$$__';

  /**
   * 获取特定时间格式
   * @param date 时间值 DateValue
   * @param format 格式 sting 默认值='YYYY-MM-DD'
   * @returns 满足格式的值或空字符串 string
   */
  getFormatDate(date: DateValue, format = 'YYYY-MM-DD'): string {
    const newDate: number | string =
      typeof date === 'number' ? date : Date.parse('' + date);
    return newDate || newDate === 0 ? moment(date).format(format) : '';
  }

  /**
   * 获取一天开始0:00:00
   * @param date moment.Moment数据类型
   * @returns 毫秒表示的时间或undefined
   */
  getDateStart(date: moment.Moment | undefined): number | undefined {
    return date && date.startOf('day').valueOf();
  }

  /**
   * 获取一天结束23:59:59
   * @param date moment.Moment数据类型
   * @returns 毫秒表示的时间或undefined
   */
  getDateEnd(date: moment.Moment | undefined): number | undefined {
    return date && date.endOf('day').valueOf();
  }

  /**
   * 如果数据为空展示占位符
   * @param value 任意类型的值
   * @param placeholder 占位符
   * @returns 非空值或占位符
   */
  formatData(value: unknown, placeholder = this.placeholder): unknown {
    return !value && value !== 0 && value !== false ? placeholder : value;
  }

  /**
   * 移除目标对象指定的属性值
   * @param obj 目标对象 object
   * @param keys 需要移除的属性值 array
   * @returns 新对象 object
   */
  removeKeys(obj: AutoObjValue = {}, keys: (string | number)[]): AutoObjValue {
    const newKeys: string[] = keys.map((d) => '' + d);
    const newObj: AutoObjValue = {};
    Object.keys(obj).forEach((key) => {
      if (!newKeys?.includes(key)) {
        newObj[key] = obj[key];
      }
    });
    return newObj;
  }

  /**
   * table数据添加key和index字段
   * @param list 表数据 array
   * @param current 当前页 number 可选
   * @param pageSize item数 number 可选
   * @returns 新数组
   */
  initTableData(
    list: AutoObjValue[],
    current?: number,
    pageSize?: number
  ): AutoObjValue[] {
    return list?.map((d, i) => {
      const index =
        current && pageSize ? (current - 1) * pageSize + i + 1 : i + 1;
      return { ...d, index, key: d.id || d.id === 0 ? d.id : index };
    });
  }

  /**
   * 通过select的value获取lable（翻译）
   * @param options select数据 array
   * @param value 值 string | number
   * @returns label
   */
  getOptionLabel(
    options: Partial<Utils.Option>[],
    value: string | number
  ): string | undefined {
    const option: Partial<Utils.Option> =
      options?.find((d) => d.value === value) || {};
    return option.label;
  }

  /**
   * 将两个值通过某种连接符组合在一起
   * @param a 值 number | string
   * @param b 值 number | string
   * @param connect 连接符 string
   * @returns 新值 string
   */
  getConnectValue(
    a: number | string,
    b: number | string,
    connect = this.connect
  ): string {
    return `${a}${connect}${b}`;
  }

  /**
   * 判断该值是否null、undefined、''、Infinity
   * @param value 任意类型
   * @returns 是为true，不是为false boolean
   */
  isFakeValue(value: unknown): boolean {
    return typeof value === 'number'
      ? !isFinite(value)
      : !value && value !== false;
  }

  /**
   * 格式化为select数据
   * @param data 数据 AutoObjValue[]
   * @param labelKey 取labelKey字段的值作为label string
   * @param valueKey 取valueKey字段的值作为value string
   * @param connect 连接符 string
   * @returns
   */
  getOptions(
    data: AutoObjValue[],
    labelKey: string | number,
    valueKey: string | number,
    connect?: string | boolean
  ): Partial<Utils.Option>[] {
    return Array.isArray(data)
      ? data.map(
          (d): Utils.Option => ({
            value: connect
              ? this.getConnectValue(
                  d[labelKey],
                  d[valueKey],
                  typeof connect === 'boolean' ? undefined : connect
                )
              : d[valueKey],
            label: d[labelKey],
          })
        )
      : [];
  }

  /**
   * 将数字千分位展示
   * @param value 目标值 number | string
   * @returns 返回千分位展示的值
   */
  formatNumber(value: number | string): string | undefined {
    const num: number = typeof value === 'string' ? parseInt(value, 10) : value;
    return isFinite(num) ? num.toLocaleString('en-US') : undefined;
  }

  /**
   * 只展示部分文字，多余部分省略号展示
   * @param value 展示内容 number | string
   * @param limit 限制字数 limit
   * @returns 处理后值 string
   */
  omitMoreText(value: number | string, limit = 15): string {
    const val = '' + value;
    return val.length > limit ? `${val.slice(0, limit)}...` : val;
  }

  /**
   * 过滤掉对象中值为假值（null、""、undefined、NaN、Infinity）的属性
   * @param data 目标对象 AutoObjValue
   * @returns 干净的对象 AutoObjValue
   */
  filterEmptyQuery(data: AutoObjValue = {}): AutoObjValue {
    const newData: AutoObjValue = {};
    Object.keys(data).forEach((key) => {
      if (!this.isFakeValue(data[key])) {
        newData[key] = data[key];
      }
    });
    return newData;
  }

  /**
   * 过滤掉数组中null、""、undefined、NaN、Infinity
   * @param arr 目标数组 unknown[]
   * @returns 新数组
   */
  filterEmptyArray(arr: unknown[]): unknown[] {
    return arr?.filter((d) => !this.isFakeValue(d));
  }

  /**
   * 获取url参数部分
   * @param url 地址 string
   * @returns 一个对象
   */
  getParamsUrl(url: string): AutoObjValue {
    const newUrl = decodeURIComponent(url);
    const queryArr = newUrl?.split('?')[1]?.split('#')[0]?.split('&');
    const queryObj: AutoObjValue = {};
    queryArr?.forEach((d) => {
      const arr = this.filterEmptyArray(d.split('='));
      if (arr[1]) {
        queryObj[arr[0] as string] = arr[1];
      }
    });
    return queryObj;
  }
}
export default Utils;
